﻿/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace DaveSexton.DocToMaml
{
	internal sealed class ConversionContext
	{
		#region Public Properties
		public int ConvertedInputsCount { get; private set; }

		public int ConvertedFilesCount { get; private set; }

		public int ErrorCount { get; private set; }
		#endregion

		#region Private / Protected
		private readonly Project project;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="ConversionContext" /> class.
		/// </summary>
		public ConversionContext(Project project)
		{
			if (project == null)
				throw new ArgumentNullException("project");

			this.project = project;
		}
		#endregion

		#region Methods
		public void ConvertAllInputs()
		{
			ConvertAllInputsInternal(project.LastOutputDirectory);
		}

		public void ConvertAllInputs(string target)
		{
			if (string.IsNullOrEmpty(target))
				target = Environment.CurrentDirectory;

			project.LastOutputDirectory = target;

			ConvertAllInputsInternal(target);
		}

		private void ConvertAllInputsInternal(string target)
		{
			ConvertedInputsCount = 0;
			ConvertedFilesCount = 0;
			ErrorCount = 0;

			InputCollection inputs = project.Inputs;

			project.Guids.EnsureGuids(inputs);

			float total = inputs.Count;

			foreach (IInput input in inputs)
			{
				ConvertEventArgs args = new ConvertEventArgs(input, (int) (ConvertedInputsCount / total * 100));

				OnBeforeConvertInput(args);

				try
				{
					ConvertedFilesCount += input.Convert(target);
				}
				catch (HtmlToMamlConversionException)
				{
					ErrorCount++;
				}

				ConvertedInputsCount = ConvertedInputsCount + 1;

				OnAfterConvertInput(args);
			}
		}
		#endregion

		#region Events
		private readonly object BeforeConvertInputEventLock = new object();
		private EventHandler<ConvertEventArgs> BeforeConvertInputEvent;
		private readonly object AfterConvertInputEventLock = new object();
		private EventHandler<ConvertEventArgs> AfterConvertInputEvent;

		/// <summary>
		/// Event raised after an input is converted.
		/// </summary>
		public event EventHandler <ConvertEventArgs>AfterConvertInput
		{
			add
			{
				lock (AfterConvertInputEventLock)
				{
					AfterConvertInputEvent += value;
				}
			}
			remove
			{
				lock (AfterConvertInputEventLock)
				{
					AfterConvertInputEvent -= value;
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="AfterConvertInput" /> event.
		/// </summary>
		/// <param name="e"><see cref="EventArgs" /> object that provides the arguments for the event.</param>
		private void OnAfterConvertInput(ConvertEventArgs e)
		{
			EventHandler<ConvertEventArgs> handler = null;

			lock (AfterConvertInputEventLock)
			{
				handler = AfterConvertInputEvent;
			}

			if (handler != null)
				handler(this, e);
		}

		/// <summary>
		/// Event raised before an input is converted.
		/// </summary>
		public event EventHandler<ConvertEventArgs> BeforeConvertInput
		{
			add
			{
				lock (BeforeConvertInputEventLock)
				{
					BeforeConvertInputEvent += value;
				}
			}
			remove
			{
				lock (BeforeConvertInputEventLock)
				{
					BeforeConvertInputEvent -= value;
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="BeforeConvertInput" /> event.
		/// </summary>
		/// <param name="e"><see cref="EventArgs" /> object that provides the arguments for the event.</param>
		private void OnBeforeConvertInput(ConvertEventArgs e)
		{
			EventHandler<ConvertEventArgs> handler = null;

			lock (BeforeConvertInputEventLock)
			{
				handler = BeforeConvertInputEvent;
			}

			if (handler != null)
				handler(this, e);
		}
		#endregion
	}
}
